package com.wsx.rpc.dubbo.plug.balance;

import com.alibaba.dubbo.common.URL;
import com.alibaba.dubbo.common.utils.StringUtils;
import com.alibaba.dubbo.rpc.Invocation;
import com.alibaba.dubbo.rpc.Invoker;
import com.alibaba.dubbo.rpc.cluster.loadbalance.AbstractLoadBalance;
import com.wsx.rpc.dubbo.plug.SwitchService;

import java.util.List;
import java.util.Random;

/**
 * @author wangshuaixin
 * @Title: com.wsx.rpc.dubbo.plug.balance.SwitchRandomBalance
 * @Description: TODO
 * @date 2018/10/31
 */
public class SwitchRandomBalance extends AbstractLoadBalance {
    public static final String NAME = "switchRandomBalance";
    private final Random random = new Random();


    @Override
    protected <T> Invoker<T> doSelect(List<Invoker<T>> list, URL url, Invocation invocation) {
        String config = invocation.getAttachments().get("switch");
        if (StringUtils.isEmpty(config)) {
            System.out.println("invocation config is null");
            config = SwitchService.getSwitch();
        }
        //如果没有切换配置则走默认的随机负载均衡
        System.out.println("switchRandomBalance：" + config );
        if (StringUtils.isEmpty(config)) {
            return randomBalance(list, invocation);
        }
        String[] configs = config.split("@");
        boolean open = configs[0].equals("1");
        if (!open) {
            return randomBalance(list, invocation);
        }
        String matches = configs[1];
        URL invokerUrl = null;
        for (Invoker<T> invoker : list) {
            if(invoker.isAvailable()) {
                invokerUrl = invoker.getUrl();
                String match = invokerUrl.getIp() + ":" + invokerUrl.getPort();
                if (matches.contains(match)) {
                    return invoker;
                }
            }
        }

        return randomBalance(list, invocation);
    }

    private <T> Invoker<T> randomBalance(List<Invoker<T>> list, Invocation invocation) {
        int length = list.size();
        int totalWeight = 0;
        boolean sameWeight = true;

        int offset;
        int i;
        for(offset = 0; offset < length; ++offset) {
            i = this.getWeight((Invoker)list.get(offset), invocation);
            totalWeight += i;
            if(sameWeight && offset > 0 && i != this.getWeight((Invoker)list.get(offset - 1), invocation)) {
                sameWeight = false;
            }
        }

        if(totalWeight > 0 && !sameWeight) {
            offset = this.random.nextInt(totalWeight);

            for(i = 0; i < length; ++i) {
                offset -= this.getWeight((Invoker)list.get(i), invocation);
                if(offset < 0) {
                    return (Invoker)list.get(i);
                }
            }
        }

        return (Invoker)list.get(this.random.nextInt(length));
    }

}
